package com.fadis.cmd;

import com.fadis.FadisException;
import com.fadis.data.FSet;
import com.fadis.data.base.StringSet;
import com.fadis.db.FadisDB;
import com.fadis.protocol.BulkString;
import com.fadis.protocol.LongNumber;
import com.fadis.protocol.RespArray;

import java.util.List;
import java.util.Set;

public class CmdSet {

    // SADD key member [member …]
    // 返回被添加到集合中的新元素的数量
    public static final class sadd implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String[] args = new String[frame.getArgsCount() - 2];
            for (int i = 2; i < frame.getArgsCount(); i++) {
                args[i-2] = frame.getArg(i);
            }
            StringSet set = FadisDB.tryToGetOrCreateSet( key, true);
            int r = FSet.sadd(set, args);
            return LongNumber.encodeInt(r);
        }
    }

    // SISMEMBER key member  判断是否存在
    // 存在返回1，其他情况都返回0
    public static final class sismember implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String member = frame.getArg(2);
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);
            Boolean r = FSet.sismember(set, member);
            return LongNumber.encodeInt(r ? 1 : 0);
        }
    }

    // SPOP key [count]   移除并返回集合中的一个随机元素
    // 返回 一个元素或数组，集合空则返回null
    public static final class spop implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String countStr = frame.getArg(2);
            int count = countStr == null ? 1 : Integer.parseInt(countStr);
            boolean needList = countStr != null;
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);

            if(set == null || set.size() == 0) return BulkString.encodedNull();
            if(!needList){
                String r = FSet.spop(set);
                if(set.size() == 0){
                    FadisDB.remove(key);
                }
                return BulkString.encodedBulkString(r);
            }else {
                Set<String> list = FSet.spop(set, count);
                if(set.size() == 0){
                    FadisDB.remove(key);
                }
                return RespArray.encodeSet(list);
            }
        }
    }

    // SRANDMEMBER key [count]
    // 返回 一个元素或数组，集合空则返回null
    /*
    关于count：
    - 正数：无重复元素的数组
    - 负数：有重复元素的数组
    - 不传：返回string
    - 0：返回null
     */
    public static final class srandmember implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String countStr = frame.getArg(2);
            int count = countStr == null ? 1 : Integer.parseInt(countStr);
            boolean needList = countStr != null;
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);

            if(set == null || set.size() == 0) return BulkString.encodedNull();
            if(!needList){
                String r = FSet.srandmember(set);
                return BulkString.encodedBulkString(r);
            }else {
                List<String> list = FSet.srandmember(set, count);
                return RespArray.encodeList(list);
            }

        }
    }

    // SREM key member [member …]  移除元素
    // 返回被成功移除的元素的数量
    public static final class srem implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String[] args = new String[frame.getArgsCount() - 2];
            for (int i = 2; i < frame.getArgsCount(); i++) {
                args[i-2] = frame.getArg(i);
            }
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);
            int r = FSet.srem(set, args);

            if(set.size() == 0){
                FadisDB.remove(key);
            }

            return LongNumber.encodeInt(r);
        }
    }

    //SMOVE source destination member
    // 将 member 元素从 source 集合移动到 destination 集合。
    //member存在返回1，否则返回0
    public static final class smove implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String source = frame.getArg(1);
            String destination = frame.getArg(2);
            String member = frame.getArg(3);
            StringSet sourceSet = FadisDB.tryToGetOrCreateSet( source, false);
            if(sourceSet == null || !sourceSet.contains(member)){
                return LongNumber.encodeInt(0);
            }else{
                StringSet destinationSet = FadisDB.tryToGetOrCreateSet( destination, true);
                FSet.smove(sourceSet, destinationSet, member);

                if(sourceSet.size() == 0){
                    FadisDB.remove(source);
                }
                return LongNumber.encodeInt(1);
            }
        }
    }

    // SCARD key
    // 返回集合 key 的基数(集合中元素的数量)，无则0
    public static final class scard implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);
            return LongNumber.encodeInt(FSet.scard(set));
        }
    }


    public static final class smembers implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringSet set = FadisDB.tryToGetOrCreateSet( key, false);
            return RespArray.encodeSet(set);
        }
    }

    // SINTER key [key …]
    // 求交集，交集为空则null，不存在的key视为空集合，类型错误返回error
    // 返回交集
    public static final class sinter implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {

            String[] args = new String[frame.getArgsCount() - 1];
            for (int i = 1; i < frame.getArgsCount(); i++) {
                args[i-1] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sinter(sets);
            if(inter == null || inter.size() == 0) inter = new StringSet();
            return RespArray.encodeSet(inter);
        }
    }

    // SINTERSTORE destination key [key …]

    // 求交集，交集为空则null，不存在的key视为空集合，类型错误返回error
    // 返回结果集中的成员数量

    // keys的交集存在集合destination中
    // -- 如果 destination 集合已经存在(即使类型不对也不报错)，则将其覆盖（删除destination，再新建）
    // -- 交集是空，则destination会被删除（如果以前存在）
    public static final class sinterstore implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String destination = frame.getArg(1);

            String[] args = new String[frame.getArgsCount() - 2];
            for (int i = 2; i < frame.getArgsCount(); i++) {
                args[i-2] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sinter(sets);
            if(inter == null || inter.size() == 0) inter = null;

            FadisDB.remove(destination);  // 无论如何，都会覆盖之前的，并且无元素就是删key

            if(inter != null){
                StringSet set = FadisDB.tryToGetOrCreateSet( destination, true);
                set.addAll(inter);
            }

            return LongNumber.encodeInt(inter == null ? 0 : inter.size());
        }
    }

    // SUNION key [key …]  并集
    // 返回新集合或null
    public static final class sunion implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String[] args = new String[frame.getArgsCount() - 1];
            for (int i = 1; i < frame.getArgsCount(); i++) {
                args[i-1] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sunion(sets);
            if(inter == null || inter.size() == 0) inter = new StringSet();
            return RespArray.encodeSet(inter);
        }
    }

    // SUNIONSTORE destination key [key …]   并集存入destination
    // 返回结果集中的元素数量。
    public static final class sunionstore implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String destination = frame.getArg(1);

            String[] args = new String[frame.getArgsCount() - 2];
            for (int i = 2; i < frame.getArgsCount(); i++) {
                args[i-2] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sunion(sets);
            if(inter == null || inter.size() == 0) inter = null;

            FadisDB.remove(destination);  // 无论如何，都会覆盖之前的，并且无元素就是删key

            if(inter != null){
                StringSet set = FadisDB.tryToGetOrCreateSet( destination, true);
                set.addAll(inter);
            }

            return LongNumber.encodeInt(inter == null ? 0 : inter.size());
        }
    }

    // SDIFF key [key …] 差集
    // 返回新集合或null
    public static final class sdiff implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String[] args = new String[frame.getArgsCount() - 1];
            for (int i = 1; i < frame.getArgsCount(); i++) {
                args[i-1] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sdiff(sets);
            if(inter == null || inter.size() == 0) inter = new StringSet();
            return RespArray.encodeSet(inter);
        }
    }

    // SDIFFSTORE destination key [key …]  差集存入destination
    // 结果集中的元素数量。
    public static final class sdiffstore implements CmdHandler{

        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String destination = frame.getArg(1);

            String[] args = new String[frame.getArgsCount() - 2];
            for (int i = 2; i < frame.getArgsCount(); i++) {
                args[i-2] = frame.getArg(i);
            }

            StringSet[] sets = new StringSet[args.length];
            for (int i = 0; i < args.length; i++) {
                StringSet set = FadisDB.tryToGetOrCreateSet( args[i], false);
                if(set == null) set = new StringSet();
                sets[i] = set;
            }
            StringSet inter = FSet.sdiff(sets);
            if(inter == null || inter.size() == 0) inter = null;

            FadisDB.remove(destination);  // 无论如何，都会覆盖之前的，并且无元素就是删key

            if(inter != null){
                StringSet set = FadisDB.tryToGetOrCreateSet( destination, true);
                set.addAll(inter);
            }

            return LongNumber.encodeInt(inter == null ? 0 : inter.size());
        }
    }


}
